using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using LiJ.Common.Core;
using LiJ.Common.Extention;
using LiJ.Common.Plugs.LogPlug;
using LiJ.Http.Extention;
using LiJ.Http.Mos;
using LiJ.Pay.Ali.Pay.SysTools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace LiJ.Pay.Ali
{
	/// <summary>
	///             支付宝接口SDK基类
	/// </summary>
	public abstract class ZPayBaseApi : BaseConfigProvider<ZPayConfig, ZPayBaseApi>
	{
		private ZPayRsaAssist _rsaAssist;

		/// <summary>
		/// 支付宝api接口地址
		/// </summary>
		protected const string m_ApiUrl = "https://openapi.alipay.com/gateway.do";

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="config"></param>
		protected ZPayBaseApi(ZPayConfig config)
			: base(config)
		{
		}

		/// <summary>
		///  加密对象提供者
		///     为了同时满足多租户多线程上下文配置， 所以这里静态线程变量赋值，如果不存在则创建
		/// </summary>
		/// <param name="config"></param>
		/// <returns></returns>
		private ZPayRsaAssist GenerateRsaAssist(ZPayConfig config)
		{
			if (base.ConfigMode == ConfigProviderMode.Context)
			{
				return new ZPayRsaAssist(config.AppPrivateKey, config.AppPublicKey, config.Charset);
			}
			if (this._rsaAssist == null)
			{
				return this._rsaAssist = new ZPayRsaAssist(config.AppPrivateKey, config.AppPublicKey, config.Charset);
			}
			return this._rsaAssist;
		}

		/// <summary>
		/// 处理远程请求方法，并返回需要的实体
		/// </summary>
		/// <typeparam name="T">需要返回的实体类型</typeparam>
		/// <param name="request">远程请求组件的request基本信息</param>
		/// <param name="respColumnName">响应实体中的内容列表</param>
		/// <param name="funcFormat">获取实体格式化方法</param>
		/// <returns>实体类型</returns>
		public async Task<T> RestCommonAsync<T>(LHttpRequest request, string respColumnName, Func<HttpResponseMessage, Task<T>> funcFormat = null) where T : ZPayBaseResp, new()
		{
			T t = null;
			try
			{
				request.AddressUrl = "https://openapi.alipay.com/gateway.do" + "?charset=" + base.ApiConfig.Charset;
				request.RequestSet = delegate(HttpRequestMessage r)
				{
					if (r.Content != null)
					{
						MediaTypeHeaderValue contentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded")
						{
							CharSet = base.ApiConfig.Charset
						};
						r.Content.Headers.ContentType = contentType;
					}
				};
				HttpResponseMessage resp = await request.RestSend(null);
				if (resp.IsSuccessStatusCode)
				{
					if (funcFormat != null)
					{
						t = await funcFormat(resp);
					}
					else
					{
						string text = await resp.Content.ReadAsStringAsync();
						JObject jObject = JObject.Parse(text);
						if (jObject == null)
						{
							T val = new T();
							val.Ret = 1420;
							val.msg = "基础请求响应不正确，请检查地址或者网络是否正常！";
							return val;
						}
						t = jObject[respColumnName].ToObject<T>();
						if (((ResultMo)(object)t).IsSuccess())
						{
							string sign = jObject["sign"].ToString();
							this.CheckSign<T>(ZPayBaseApi.GetCehckSignContent(respColumnName, text), sign, t);
						}
						else
						{
							t.msg = t.msg + "-" + t.sub_msg;
						}
					}
				}
			}
			catch (Exception ex)
			{
				string str = LogUtil.Error("基类请求出错，错误信息：" + ex.Message, "Z_RestCommon", "social_center");
				T val2 = new T();
				val2.Ret = 1500;
				val2.msg = "基类请求出错，请检查网络是否正常，错误码：" + str;
				t = val2;
			}
			return t;
		}

		/// <summary>
		///   发起post请求
		/// </summary>
		/// <typeparam name="TReq"></typeparam>
		/// <typeparam name="TResp"></typeparam>
		/// <param name="apiMethod"></param>
		/// <param name="respColumnName"></param>
		/// <param name="req"></param>
		/// <returns></returns>
		public async Task<TResp> PostApiAsync<TReq, TResp>(string apiMethod, string respColumnName, TReq req) where TReq : ZPayBaseReq where TResp : ZPayBaseResp, new()
		{
			ResultMo<IDictionary<string, string>> reqBodyDics = this.GetReqBodyDics<TReq>(apiMethod, req);
			if (!reqBodyDics.IsSuccess())
			{
				return ResultMoMap.ConvertToResult<TResp>((ResultMo)reqBodyDics);
			}
			LHttpRequest request = new LHttpRequest
			{
				HttpMothed = HttpMothed.Post,
				CustomBody = ZPayBaseApi.ConvertDicToEncodeReqBody(reqBodyDics.Data)
			};
			return await this.RestCommonAsync<TResp>(request, respColumnName, (Func<HttpResponseMessage, Task<TResp>>)null);
		}

		/// <summary>
		///  返回结果验签
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="signContent"></param>
		/// <param name="sign"></param>
		/// <param name="t"></param>
		protected void CheckSign<T>(string signContent, string sign, T t) where T : ResultMo, new()
		{
			try
			{
				ZPayRsaAssist zPayRsaAssist = this.GenerateRsaAssist(base.ApiConfig);
				bool flag = zPayRsaAssist.CheckSign(signContent, sign);
				if (!flag)
				{
					if (!string.IsNullOrEmpty(signContent) && signContent.Contains("\\/"))
					{
						signContent = signContent.Replace("\\/", "/");
						flag = zPayRsaAssist.CheckSign(signContent, sign);
					}
					if (!flag)
					{
						t.Ret = 1425;
						t.Msg = "当前签名非法！";
					}
				}
			}
			catch (Exception ex)
			{
				t.Ret = 1500;
				t.Msg = "解密签名过程中出错，详情请查看日志";
				LogUtil.Info(string.Format("解密签名过程中出错，解密内容：{0}, 待验证签名：{1}, 错误信息：{2}", signContent, sign, ex.Message), "CheckSign", "pay_center");
			}
		}

		/// <summary>
		///  获取需要验签的内容部分
		/// </summary>
		/// <param name="respColumnName"></param>
		/// <param name="contentStr"></param>
		/// <returns></returns>
		private static string GetCehckSignContent(string respColumnName, string contentStr)
		{
			int num = contentStr.IndexOf(respColumnName, StringComparison.Ordinal) + respColumnName.Length + 2;
			int num2 = contentStr.LastIndexOf(',');
			return contentStr.Substring(num, num2 - num);
		}

		/// <summary>
		/// 补充默认属性并返回请求内容
		/// </summary>
		/// <param name="method">接口方法名</param>
		/// <param name="req">请求实体</param>
		/// <returns>返回最终的内容</returns>
		protected internal ResultMo<IDictionary<string, string>> GetReqBodyDics<T>(string method, T req) where T : ZPayBaseReq
		{
			SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
			try
			{
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "app_id", base.ApiConfig.AppId);
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "charset", base.ApiConfig.Charset);
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "method", method);
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "notify_url", req.GetNotifyUrl());
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "return_url", req.GetReturnUrl());
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "sign_type", "RSA2");
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "format", base.ApiConfig.Format);
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "version", base.ApiConfig.Version);
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
				ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "biz_content", JsonConvert.SerializeObject(req, Formatting.None, new JsonSerializerSettings
				{
					NullValueHandling = NullValueHandling.Ignore,
					DefaultValueHandling = DefaultValueHandling.Ignore
				}));
				if (req.app_auth_token != null)
				{
					ZPayBaseApi.SetDefaultPropertyFormat(sortedDictionary, "app_auth_token", req.app_auth_token.app_auth_token);
				}
				string data = string.Join("&", from d in sortedDictionary
				select d.Key + "=" + d.Value);
				string value = this.GenerateRsaAssist(base.ApiConfig).GenerateSign(data);
				sortedDictionary.Add("sign", value);
			}
			catch (Exception ex)
			{
				LogUtil.Error("处理签名字典出错，详细信息：" + ex.Message, "Z_GetReqBodyDics", "pay_center");
				return new ResultMo<IDictionary<string, string>>(1500, "处理签名字典出错，详细信息请查看日志");
			}
			return new ResultMo<IDictionary<string, string>>((IDictionary<string, string>)sortedDictionary);
		}

		private static void SetDefaultPropertyFormat(IDictionary<string, string> dirs, string key, string value)
		{
			if (!string.IsNullOrEmpty(value))
			{
				dirs[key] = value;
			}
		}

		/// <summary>
		///  转化生成签名后的请求内容
		/// </summary>
		/// <param name="dics"></param>
		/// <returns></returns>
		protected static string ConvertDicToEncodeReqBody(IDictionary<string, string> dics)
		{
			return string.Join("&", from d in dics
			select d.Key + "=" + d.Value.UrlEncode());
		}

		/// <inheritdoc />
		protected override ZPayConfig GetDefaultConfig()
		{
			return ZPayConfigProvider.DefaultConfig;
		}
	}
}
